using System.Windows;
using NavigateExample.Services.Dialog;
using NavigateExample.ViewModels;

//DialogService控制着子窗口的打开以及关闭
//通过事件订阅, 监听对话框的关闭事件，并返回结果以及参数在窗口关闭后回调
//路径1：ViewModel主动关闭（RequestClose事件）
//路径2：用户直接关闭（X按钮/ESC键)
//callback(result)回调是在子窗口关闭后执行的，拿到结果以及参数
namespace NavigateExample.Services
{
    // 对话框服务实现类
    public class DialogService : IDialogService
    {
        private readonly IServiceProvider _serviceProvider;
        public DialogService(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
        }
        // 显示对话框
        public void ShowDialog<TDialogView>(DialogParameters parameters, Action<IDialogResult> callback) where TDialogView : Window
        {
            CreateAndShowDialog<TDialogView>(parameters, callback);
        }
        // 显示对话框（无参数）
        public void ShowDialog<TDialogView>(Action<IDialogResult> callback) where TDialogView : Window
        {
            ShowDialog<TDialogView>(new DialogParameters(), callback);
        }
        // 简单显示对话框
        public void ShowDialog<TDialogView>() where TDialogView : Window
        {
            ShowDialog<TDialogView>(new DialogParameters(), _ => { });
        }
        // 创建并显示对话框
        private void CreateAndShowDialog<TDialogView>(DialogParameters parameters, Action<IDialogResult> callback) where TDialogView : Window
        {
            IDialogResult? finalResult = null;
            bool dialogClosed = false;
            try
            {
                // 从DI容器获取对话框窗口（应该在view后台代码已经配置好DataContext）
                var dialogWindow = _serviceProvider.GetRequiredService<TDialogView>();
                // 获取ViewModel（通过DataContext）
                var viewModel = dialogWindow.DataContext;
                // 如果ViewModel实现了IDialogAware接口
                if (viewModel is IDialogAware dialogAware)
                {
                    // 设置窗口标题
                    if (!string.IsNullOrEmpty(dialogAware.Title))
                    {
                        dialogWindow.Title = dialogAware.Title;
                    }
                    // 【1】订阅RequestClose事件：ViewModel主动请求关闭
                    Action<IDialogResult> requestCloseHandler = (result) =>
                    {
                        // 检查是否可以关闭对话框
                        if (dialogAware.CanCloseDialog() && !dialogClosed)
                        {
                            // 标记对话框已关闭（必须在Close()之前设置，防止Closing事件重复处理）
                            dialogClosed = true;
                            finalResult = result;
                            // 设置对话框结果并关闭
                            // 模态窗口的DialogResult设置为true或false时，窗口会自动关闭
                            dialogWindow.DialogResult = result.Result != ButtonResult.Cancel;
                            //设置DialogResult→触发Closing事件→触发Closed事件→ShowDialog()返回DialogResult

                        }
                        // 如果不能关闭，则不执行任何操作，保持对话框打开状态
                    };
                    dialogAware.RequestClose += requestCloseHandler;
                    // 【2】处理窗口的Closing事件：用户点击X按钮或按ESC键
                    // 如果用户直接点击窗口右上角的关闭按钮DialogResult保持为null，它不会被自动设置为false
                    dialogWindow.Closing += (sender, e) =>
                    {
                        // 如果ViewModel不允许关闭，则取消关闭操作
                        if (!dialogAware.CanCloseDialog())
                        {
                            e.Cancel = true;
                            return;
                        }
                        // 如果是通过X按钮等方式关闭，且还没有设置结果
                        if (!dialogClosed)
                        {
                            dialogClosed = true;
                            // 根据DialogResult设置最终结果
                            var result = sender is Window window && window.DialogResult == true 
                                ? ButtonResult.OK 
                                : ButtonResult.Cancel;
                            finalResult = new DialogResult(result);
                        }
                    };
                    // 处理窗口Closed事件：确保清理工作
                    dialogWindow.Closed += (sender, e) =>
                    {
                        // 清理事件订阅
                        dialogAware.RequestClose -= requestCloseHandler;
                        // 调用OnDialogClosed生命周期方法
                        dialogAware.OnDialogClosed();
                    };
                    
                    // 调用对话框打开生命周期方法（在显示之前）
                    dialogAware.OnDialogOpened(parameters);
                }
                else
                {
                    // 对于非IDialogAware的对话框，使用简单的处理逻辑
                    dialogWindow.Closed += (sender, e) =>
                    {
                        if (!dialogClosed)
                        {
                            dialogClosed = true;
                            var result = dialogWindow.DialogResult == true ? ButtonResult.OK : ButtonResult.Cancel;
                            finalResult = new DialogResult(result);
                        }
                    };
                }
                
                // 设置对话框属性
                dialogWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                dialogWindow.Owner = Application.Current.MainWindow;
                dialogWindow.ShowInTaskbar = false;
                
                // 显示模态对话框（阻塞调用，直到对话框关闭）
                dialogWindow.ShowDialog();
                
                // 对话框关闭后，执行唯一的回调
                // 此时finalResult必定已经被设置（要么通过RequestClose，要么通过Closing事件）
                if (finalResult != null)
                {
                    callback?.Invoke(finalResult);
                }
                else
                {
                    // 理论上不应该到达这里，但作为保险措施
                    callback?.Invoke(new DialogResult(ButtonResult.Cancel));
                }
            }
            catch (Exception ex)
            {
                // 发生异常时返回错误结果
                var errorParameters = new DialogParameters();
                errorParameters.Add("Error", ex.Message);
                callback?.Invoke(new DialogResult(ButtonResult.None, errorParameters));
            }
        }
    }
}